//
// Created by 15760 on 2022/11/8.
//

#include "round.h"
#include <iostream>
#include "dice.h"


using namespace std;

void Round::play() {  //遍历所有玩家
    unsigned int in;
    bool finished = false;
    while (true) {
        for (size_t i = 0; i < Game::getNumOfPlayers(); i++) {  //对每位玩家进行相同的游戏操作
            cout << "***************************** Now is the round of player " << i + 1 << " *****************************" << endl;
            //先掷骰子，需要判断当前玩家是否有火车站
            Player &p = Game::getInstance().getPlayer(i);
//        Player &p = *players[i];
            in = 1;  //默认扔1个骰子
            if (p.haveTrainStation()) {
                cout << "You have the train station, so you can choose to roll 1 or 2 dices(1~2): ";
                cin >> in;
                while (in != 1 && in != 2) {
                    cout << "Wrong input, please input again (1 or 2): ";
                    cin >> in;
                }
            }
            Dice dice(in);
            unsigned int points = dice.getPoints();
            cout << "The total number of dice points is: " << points << "\n";

            //掷完骰子查看是否触发在场玩家的建筑，如果触发则得钱或失钱
            checkAllCardsForEachPlayer(points, p);

            //如果有钱可以选择是否购买建筑
            Coin &pCoin = p.getCoin();
            if (pCoin.getSum() > 0) {
                cout << "--------------------------------------------------------------------------------" << endl;
                cout << "Now on the table, there are [name(cost)]: \n";
                cout << "You have " << pCoin.getSum() << " coins." << "\n";
                landmarkBuildings.printAllCards(cout);
                ordinaryBuildings.printAllCards(cout);
                cout << endl;
                cout << "--------------------------------------------------------------------------------" << endl;
                cout << "Please choose a card that you want to buy(0 to pass, 111 to check all your cards): ";
                cin >> in;
                if (in != 0) {//当输入的in超过目前牌桌上可购买的牌时，警告，让玩家重新输入
                    if (in == 111) { //输入111，输出当前玩家所有卡牌
                        cout << "Now you have these cards:\n" << p.getCards() << endl;
                        cout << "Then please choose a card that you want to buy(0 to pass): ";
                        cin >> in;
                    }
                    if (in != 0) {
                        while (in >
                               OrdinaryBuildings::numOfOrdinaryBuildings + LandmarkBuildings::numOfLandmarkBuildings) {
                            cout << "Wrong input, please input again: ";
                            cin >> in;
                        }
                        unsigned int cost;
                        bool buy = true;
                        if (in <= LandmarkBuildings::numOfLandmarkBuildings) {//玩家想要购买的是地标建筑
                            cost = landmarkBuildings.getCard(in - 1).getCost();
                        } else {//玩家想要购买的是普通建筑
                            cost = ordinaryBuildings.getCard(
                                    in - LandmarkBuildings::numOfLandmarkBuildings - 1).getCost();
                        }
                        while (pCoin.getSum() < cost) {//钱不够购买该建筑物
                            cout << "You don't have enough coins to buy this card, choose another please(0 to pass): ";
                            cin >> in;
                            if (in == 0) {
                                buy = false;
                                break;
                            }
                            if (in <= LandmarkBuildings::numOfLandmarkBuildings) {//玩家想要购买的是地标建筑
                                cost = landmarkBuildings.getCard(in - 1).getCost();
                            } else {//玩家想要购买的是普通建筑
                                cost = ordinaryBuildings.getCard(
                                        in - LandmarkBuildings::numOfLandmarkBuildings - 1).getCost();
                            }
                        }
                        //钱够买建筑，将该卡牌添加到当前玩家的cards中，并从玩家那里扣除相应的金币，然后从相应的Pile中删除该牌
                        if (buy) {//玩家购买了卡片
                            if (in <= LandmarkBuildings::numOfLandmarkBuildings) {//玩家想要购买的是地标建筑
                                const Card &cardToBuy = landmarkBuildings.getCard(in - 1);
                                if (p.haveSameTypeCard(cardToBuy)) { //拥有该地标建筑
                                    cout << "You have this card, and you can\'t buy one more." << endl;
                                } else {
                                    cout << "You have bought the card " << cardToBuy << "." << endl;
                                    p.addACard(cardToBuy);
                                    landmarkBuildings.deleteACard(cardToBuy);
                                    pCoin.changeCoin(-cost);
                                }
                            } else {//玩家想要购买的是普通建筑
                                const Card &cardToBuy = ordinaryBuildings.getCard(
                                        in - LandmarkBuildings::numOfLandmarkBuildings - 1);
                                if ((cardToBuy.getType() == 6 ||
                                     cardToBuy.getType() == 7 ||
                                     cardToBuy.getType() == 8) && p.haveSameTypeCard(cardToBuy)) {
                                    cout << "You have this card, and you can\'t buy one more." << endl;
                                } else {
                                    cout << "You have bought the card " << cardToBuy << "." << endl;
                                    p.addACard(cardToBuy);
                                    ordinaryBuildings.deleteACard(cardToBuy);
                                    pCoin.changeCoin(-cost);
                                }
                            }
                            if (win(p)) {  //判断当前玩家是否获胜
                                cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>> Player " << p.getNo() + 1
                                     << " won ! <<<<<<<<<<<<<<<<<<<<<<<<<<<";
                                finished = true;
                                break;
                            }
                        }
                    }
                }
            } else {//玩家的金币数为0，自动跳过购买卡片的环节
                cout << "You don't have any coins, so pass this round.\nPress the enter to the next player."<<endl;
            }
        }
        if (finished) break;
    }
}

void Round::checkAllCardsForEachPlayer(unsigned int points, Player &pl) {
    //pl为当前掷骰子的玩家
    //对每名玩家都进行判断
    for (size_t i = 0; i < Game::getNumOfPlayers(); i++) {
        Player &p = Game::getInstance().getPlayer(i);  //遍历到玩家p
        Coin &pCoin = p.getCoin();  //每个玩家的金币
        Coin &plCoin = pl.getCoin();    //掷骰子的玩家的金币

        for (auto it = p.begin(); it != p.end(); it++) {
            if ((*it)->isTriggeringTheCard(points)) {//当前玩家有牌被触发
                //分情况讨论，判断是那张牌被触发
                //蓝色卡牌触发时所有玩家都得钱
                if ((*it)->getType() == 0 || (*it)->getType() == 9 || (*it)->getType() == 10 || (*it)->getType() == 11) {
                    cout << "Player " << p.getNo() + 1 << " gets 1 coin from the bank." << endl;
                    pCoin.changeCoin(1);     //起始麦田，麦田，农场，林场
                }
                else if ((*it)->getType() == 13) {
                    cout << "Player " << p.getNo() + 1 << " gets 3 coins from the bank." << endl;
                    pCoin.changeCoin(3);   //果园
                }
                else if ((*it)->getType() == 12) {
                    cout << "Player " << p.getNo() + 1 << " gets 5 coins from the bank." << endl;
                    pCoin.changeCoin(5);  //矿场
                }
                if (p == pl) {  //当遍历到掷骰子的玩家时
                    if ((*it)->getType() == 6) { //当前玩家有商业中心，可以选择一名玩家交换一张牌
                        /*选一名玩家交换除了地标建筑和专业建筑之外的牌*/
                        cout << "You can choose a player to exchange a card with him/her." << "\n";
                        cout << "Please choose the player(1~" << Game::getNumOfPlayers() << " or 0 to pass): ";
                        unsigned int in;
                        cin >> in;
                        while (in > Game::getNumOfPlayers() || in == 0) {
                            cout << "Wrong input, please input 1~" << Game::getNumOfPlayers()
                                 << "(0 to pass): ";
                            cin >> in;
                        }
                        Player &pToExchange = Game::getInstance().getPlayer(in - 1);
                        if (in != 0) { //该玩家想要换牌
                            vector<Card *> cv;
                            //将当前玩家的所有能交换的牌全部添加到cv容器中
                            for (auto it2 = p.begin(); it2 != p.end(); it2++) {
                                if (cardCanBeExchanged(*(*it2))) {
                                    cv.push_back(*it2);
                                }
                            }
                            cout << endl;
                            cout << "All your cards above can be exchanged: \n";
                            cout << cv << endl;
                            cout << "Select the card you want to exchange: ";
                            cin >> in;
                            while (in > cv.size() || in == 0) {
                                cout << "Wrong input, please input 1~" << cv.size() << ": ";
                                cin >> in;
                            }
                            const Card &pCard = *cv[in - 1];  //玩家想要更换的自己的牌
                            cv.clear();
                            for (auto it3 = pToExchange.begin(); it3 != pToExchange.end(); it3++) {
                                if (cardCanBeExchanged(*(*it3))) {
                                    cv.push_back(*it3);
                                }
                            }
                            cout << "All the player " << pToExchange.getNo() + 1 << "\'s cards above can be exchanged: "
                                 << "\n";
                            cout << cv << endl;
                            cout << "Select the card you want to exchange: ";
                            cin >> in;
                            while (in > cv.size() || in == 0) {
                                cout << "Wrong input, please input 1~" << cv.size() << ": ";
                                cin >> in;
                            }
                            const Card &pToExchangeCard = *cv[in - 1];
                            exchangeTwoCards(p, pCard, pToExchange, pToExchangeCard);
                        }
                    } else if ((*it)->getType() == 7) {   //体育馆：从每个玩家得2个金币
                        for (size_t k = 0; k < Game::getNumOfPlayers(); k++) {
                            Player &pla = Game::getInstance().getPlayer(k);
                            if (!(pla == pl)) {
                                Coin &plaCoin = pla.getCoin();
                                if (plaCoin.getSum() >= 2) {    //判断钱是否够给
                                    cout << "Player " << pl.getNo() + 1 << " gets 2 coins from player " << pla.getNo() + 1  << "." << endl;
                                    plaCoin.changeCoin(-2);
                                    plCoin.changeCoin(2);
                                } else if (plaCoin.getSum() < 2) {  //钱不够的话，有多少钱就拿多少
                                    if (plaCoin.getSum() == 1)
                                        cout << "Player " << pl.getNo() + 1 << " gets 1 coin from player " << pla.getNo() + 1 << "." << endl;
                                    else
                                        cout << "Player " << pl.getNo() + 1 << " gets " << plaCoin.getSum() << " coins from player " << pla.getNo() + 1 << "."  << endl;
                                    plaCoin.changeCoin(-plaCoin.getSum());
                                    plCoin.changeCoin(plaCoin.getSum());
                                }
                            }
                        }
                    } else if ((*it)->getType() == 8) {   //电视台：选一名玩家获得他的5个金币
                        unsigned int in;
                        for (size_t j=0; j<Game::getNumOfPlayers(); j++) {
                            if (j != pl.getNo()) {  //不输出当前玩家的金币数量，输出其他玩家的金币数量
                                cout << "Player " << j + 1 << " has " << Game::getInstance().getPlayer(j).getCoin().getSum() << " coins." << endl;
                            }
                        }
                        cout << "You have the TV station, so you can select a player to give you 5 coins(1~" << Game::getNumOfPlayers()
                             << "): ";
                        cin >> in;
                        while (!(in >= 1 && in <= Game::getNumOfPlayers()) || in == pl.getNo()) { //输入不能为玩家自己
                            cout << "Wrong input, please input 1~" << Game::getNumOfPlayers() << "(not "<< pl.getNo() + 1 << ")" << " :";
                            cin >> in;
                        }
                        Player &pla = Game::getInstance().getPlayer(in - 1);
                        Coin &plaCoin = pla.getCoin();
                        if (plaCoin.getSum() >= 5) {
                            cout << "Player " << pl.getNo() + 1 << " gets 5 coins from player " << pla.getNo() + 1 << "." << endl;
                            plaCoin.changeCoin(-5);
                            plCoin.changeCoin(5);
                        } else {
                            if (plaCoin.getSum() <= 1)
                                cout << "Player " << pl.getNo() + 1 << " gets " << plaCoin.getSum() << " coin from player " << pla.getNo() + 1 << "." << endl;
                            else
                                cout << "Player " << pl.getNo() + 1 << " gets " << plaCoin.getSum() << " coins from player " << pla.getNo() + 1 << "."  << endl;
                            plaCoin.changeCoin(-plaCoin.getSum());
                            plCoin.changeCoin(plaCoin.getSum());
                        }
                    } else if ((*it)->getType() == 1 || (*it)->getType() == 16) {     //触发面包店并判断是否有购物中心
                        bool b=false;
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 4) b=true;
                            if(b==true){
                                cout << "Player " << pl.getNo() + 1 << " gets 2 coins from the bank." << endl;
                                plCoin.changeCoin(2);
                            }
                            else {
                                cout << "Player " << pl.getNo() + 1 << " gets 1 coin from the bank." << endl;
                                plCoin.changeCoin(1);
                            }
                    } else if ((*it)->getType() == 17) {  //触发便利店并判断是否有购物中心
                        bool b=false;
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 4) b=true;
                            if(b==true){
                                cout << "Player " << pl.getNo() + 1 << " gets 4 coins from the bank." << endl;
                                plCoin.changeCoin(4);
                            }else {
                                cout << "Player " << pl.getNo() + 1 << " gets 3 coins from the bank." << endl;
                                plCoin.changeCoin(3);
                            }
                    } else if ((*it)->getType() == 18) {   //触发奶酪工厂并判断有无农场
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 10) {
                                cout << "Player " << pl.getNo() + 1 << " gets 3 coins from the bank." << endl;
                                plCoin.changeCoin(3);
                            }
                    } else if ((*it)->getType() == 19) {   //触发家具工厂并判断有无林场和矿场
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 11 || (*IT)->getType() == 12) {
                                cout << "Player " << pl.getNo() + 1 << " gets 3 coins from the bank." << endl;
                                plCoin.changeCoin(3);
                            }
                    } else if ((*it)->getType() == 20) {   //触发蔬菜超市并判断有无麦田
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 0 || (*IT)->getType() == 9) {
                                cout << "Player " << pl.getNo() + 1 << " gets 2 coins from the bank." << endl;
                                plCoin.changeCoin(2);}
                    }
                } else {  //除掷骰子玩家之外的玩家
                    if ((*it)->getType() == 14) {    //触发咖啡馆并判断有无购物中心
                        bool b=false;
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 4) b=true;
                        if(b==true){
                                if (plCoin.getSum() >= 2) {
                                    cout << "Player " << p.getNo() + 1 << " gets 2 coins from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-2);
                                    pCoin.changeCoin(2);
                                } else if (plCoin.getSum() < 2) {
                                    cout << "Player " << p.getNo() + 1 << " gets "<< plCoin.getSum() <<" coin from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-plCoin.getSum());
                                    pCoin.changeCoin(plCoin.getSum());
                                }
                            } else {
                                if (plCoin.getSum() == 1) {
                                    cout << "Player " << p.getNo() + 1 << " gets 1 coin from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-1);
                                    pCoin.changeCoin(1);
                                } else if (plCoin.getSum() < 1) {
                                    cout << "Player " << p.getNo() + 1 << " gets 0 coin from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(0);
                                    pCoin.changeCoin(0);
                                }
                            }
                    } else if ((*it)->getType() == 15) {    //触发西餐厅并判断有无购物中心
                        bool b=false;
                        for (typename vector<Card *>::iterator IT = p.begin(); IT != p.end(); IT++)
                            if ((*IT)->getType() == 4) b=true;
                            if(b==true){
                                if (plCoin.getSum() >= 3) {
                                    cout << "Player " << p.getNo() + 1 << " gets 3 coins from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-3);
                                    pCoin.changeCoin(3);
                                } else if (plCoin.getSum() < 3) {
                                    if(plCoin.getSum()==1){
                                        cout << "Player " << p.getNo() + 1 << " gets 1 coin from player " << pl.getNo() + 1 << "." << endl;
                                        plCoin.changeCoin(-1);
                                        pCoin.changeCoin(1);
                                    }else{
                                    cout << "Player " << p.getNo() + 1 << " gets "<< plCoin.getSum() <<" coins from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-plCoin.getSum());
                                    pCoin.changeCoin(plCoin.getSum());
                                    }
                                }
                            } else {
                                if (plCoin.getSum() >= 2) {
                                    cout << "Player " << p.getNo() + 1 << " gets 2 coins from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-2);
                                    pCoin.changeCoin(2);
                                } else if (plCoin.getSum() < 2) {
                                    cout << "Player " << p.getNo() + 1 << " gets "<< plCoin.getSum() <<" coin from player " << pl.getNo() + 1 << "." << endl;
                                    plCoin.changeCoin(-plCoin.getSum());
                                    pCoin.changeCoin(plCoin.getSum());
                                }
                            }
                        }
                    }
                }
            }
        }
}

const bool Round::win(Player &player) const {
    int count = 0;
    unsigned int allLandmarkBuildings[] = {2, 3, 4, 5};
    for (auto it = player.begin(); it != player.end(); it++) {
        for (auto i : allLandmarkBuildings) {
            if (i == (*it)->getType()) count++;
        }
    }
    if (count == 4) return true;
    else return false;
}

void Round::exchangeTwoCards(Player &p1, const Card &c1, Player &p2, const Card &c2) {
    for (auto pos = p1.begin(); pos != p1.end(); pos++) {
        if (**pos == c1) {
            p1.exchangeACard(pos, c2);
        }
    }
    for (auto pos = p2.begin(); pos != p2.end(); pos++) {
        if (**pos == c2) {
            p2.exchangeACard(pos, c1);
        }
    }
}

const bool Round::cardCanBeExchanged(Card &card) const {
        unsigned int allCardsCanBeExchanged[] = {0, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
        for (auto n: allCardsCanBeExchanged) {
            if (card.getType() == n) return true;
        }
        return false;
}
